﻿/****************************************************************************
 * ClientConnectionHandler
 * Handles the client connection and I/O
 * 
 * 20110608 - md - Exc handling 
 * *************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using OpenNI;
using NITE;
using System.Net;
using System.Collections;

namespace ConsoleServer
{
    class ClientConnectionHandler
    {
        private TcpClient clientSocket;
        private StreamReader inputStream;
        private StreamWriter outputStream;
        private NetworkStream networkStream;
        private bool bailOut;
        private KinectGestureDetector kinectHandle;
        private HashSet<String> subscribtions = new HashSet<String>();

        public event EventHandler<EventArgs> DisconnectedEvent;

        public String getRemoteAddress()
        {
            IPEndPoint e = (IPEndPoint)clientSocket.Client.RemoteEndPoint;
            return e.Address + ":" + e.Port;
        }

        public String[] getSubscribtions()
        {
            return subscribtions.ToArray();            
        }
        public ClientConnectionHandler(TcpClient socket, KinectGestureDetector kinect, MainServerThread manager)
        {
            clientSocket = socket;
            networkStream = clientSocket.GetStream();
            inputStream = new StreamReader(clientSocket.GetStream());
            outputStream = new StreamWriter(clientSocket.GetStream());
            outputStream.AutoFlush = true;
            kinectHandle = kinect;            
            new Thread(handleIO).Start();
        }

        public void distribute(String cmd)
        {
            try
            {
                outputStream.WriteLine(cmd);
            }
            catch (Exception)
            {
                Console.WriteLine("Could not send '" + cmd + "'");
            }
        }
        public void handleIO()
        {
            bailOut = false;
            try
            {
                while (clientSocket.Connected && !bailOut)
                {

                    if (networkStream.DataAvailable && !bailOut)
                    {
                        try
                        {
                            /*while (!inputStream.EndOfStream)
                            {*/
                            String s = inputStream.ReadLine();
                            Console.WriteLine("Received: {0}", s);
                            outputStream.WriteLine(handleCommand(s));
                            //    }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Broken read: " + e.Message);
                        }
                    }

                }
            }
            finally
            {
                // Unsubscribe all events
                kinectHandle.ClickGesture -= onClick;
                kinectHandle.SwipeDownGesture -= onSwipeDown;
                kinectHandle.SwipeUpGesture -= onSwipeUp;
                kinectHandle.SwipeLeftGesture -= onSwipeLeft;
                kinectHandle.SwipeRightGesture -= onSwipeRight;
                kinectHandle.GeneralSwipeGesture -= onGeneralSwipe;
                kinectHandle.SessionStartEvent -= onSessionStart;
                kinectHandle.SessionEndEvent -= onSessionEnd;
                kinectHandle.WaveGesture -= onWave;
                DisconnectedEvent(this, null);
                Console.WriteLine("Subscribtions cancelled");
            }
        
            Console.WriteLine("Client disconnected");
            clientSocket.Close();
        }

        private String handleCommand(String s)
        {
            if (s.Equals("SUBSCRIBE CLICK"))
            {
                kinectHandle.ClickGesture += onClick;
                subscribtions.Add("CLICK");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SWIPEDOWN"))
            {
                kinectHandle.SwipeDownGesture += onSwipeDown;
                subscribtions.Add("SWIPEDOWN");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SWIPEUP"))
            {
                kinectHandle.SwipeUpGesture += onSwipeUp;
                subscribtions.Add("SWIPEUP");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SWIPELEFT"))
            {
                kinectHandle.SwipeLeftGesture += onSwipeLeft;
                subscribtions.Add("SWIPELEFT");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SWIPERIGHT"))
            {
                kinectHandle.SwipeRightGesture += onSwipeRight;
                subscribtions.Add("SWIPERIGHT");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE GENERALSWIPE"))
            {
                kinectHandle.GeneralSwipeGesture += onGeneralSwipe;
                subscribtions.Add("GENERALSWIPE");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SESSIONSTART"))
            {
                kinectHandle.SessionStartEvent += onSessionStart;
                subscribtions.Add("SESSIONSTART");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE SESSIONEND"))
            {
                kinectHandle.SessionEndEvent += onSessionEnd;
                subscribtions.Add("SESSIONEND");
                return "OK";
            }
            else if (s.Equals("SUBSCRIBE WAVE"))
            {
                kinectHandle.WaveGesture += onWave;
                subscribtions.Add("WAVE");
                return "OK";
            }
            else if (s.Equals("QUIT"))
            {
                bailOut = true;
                return "OK";
            }
            else if (s.Equals("ENUMERATE GESTURES"))
            {
                return kinectHandle.enumerateGestures();
            }
            else if (s.Equals("SWIPE_USE_STEADY"))
            {
                kinectHandle.setUseSteadyForSwipe(true);
                return "OK";
            }
            else if (s.Equals("SWIPE_DONT_USE_STEADY"))
            {
                kinectHandle.setUseSteadyForSwipe(false);
                return "OK";
            }
            else if (s.Contains("SWIPE_STEADY_DURATION"))
            {
                String[] parts = s.Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length > 1)
                {
                    try
                    {
                        Int16 val = Convert.ToInt16(parts[1]);
                        kinectHandle.setSteadyDurationForSwipe(val);
                        return "OK";
                    }
                    catch (Exception)
                    {
                        return "ERROR";
                    }

                }
                else
                {
                    return "ERROR";
                }
            }
            else if (s.Contains("STEADY_DURATION"))
            {
                String[] parts = s.Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length > 1)
                {
                    try
                    {
                        Int16 val = Convert.ToInt16(parts[1]);
                        kinectHandle.setSteadyDuration(val);
                        return "OK";
                    }
                    catch (Exception)
                    {
                        return "ERROR";
                    }

                }
                else
                {
                    return "ERROR";
                }
            }
            return "ERROR";
        }
        void onClick(object sender, GestureRecognizedEventArgs e)
        {
            try
            {
                outputStream.WriteLine("CLICK " + e.IdentifiedPosition + " " + e.EndPosition.X + " " + e.EndPosition.Y + " " + e.EndPosition.Z);
            }
            catch (Exception ex42)
            {
                Console.WriteLine("Exception: " + ex42);
            }
        }

        void onSwipeDown(object sender, VelocityAngleEventArgs e)
        {
            try
            {
                outputStream.WriteLine("SWIPEDOWN " + e.Angle + " " + e.Velocity);
            }
            catch (Exception ex1)
            {
                Console.WriteLine("Exception: " + ex1);
            }
            
        }
        void onSwipeUp(object sender, VelocityAngleEventArgs e)
        {
             try
            {outputStream.WriteLine("SWIPEUP " + e.Angle + " " + e.Velocity);
            }
            catch (Exception e2)
            {
                Console.WriteLine("Exception: " + e2);
            }
        }
        void onSwipeLeft(object sender, VelocityAngleEventArgs e)
        {
            try
            { outputStream.WriteLine("SWIPELEFT " + e.Angle + " " + e.Velocity);
}
            catch (Exception e3)
            {
                Console.WriteLine("Exception: " + e3);
            }
        }
        void onSwipeRight(object sender, VelocityAngleEventArgs e)
        {
             try
            {outputStream.WriteLine("SWIPERIGHT " + e.Angle + " " + e.Velocity);
}
            catch (Exception e4)
            {
                Console.WriteLine("Exception: " + e4);
            }

        }
        void onGeneralSwipe(object sender, DirectionVelocityAngleEventArgs e)
        {
            try
            { outputStream.WriteLine("GENERALSWIPE " + e.Direction + " " + e.Angle + " " + e.Velocity);  
}
            catch (Exception e5)
            {
                Console.WriteLine("Exception: " + e5);
            }          
        }
        void onSessionStart(object sender, PositionEventArgs e)
        {
            try
            { outputStream.WriteLine("SESSIONSTART {0} {1} {2}", e.Position.X, e.Position.Y, e.Position.Z);  
}
            catch (Exception e6)
            {
                Console.WriteLine("Exception: " + e6);
            }          
        }

        void onSessionEnd(object sender, EventArgs e)
        {
            try
            { outputStream.WriteLine("SESSIONEND");
}
            catch (Exception e7)
            {
                Console.WriteLine("Exception: " + e7);
            }
        }

        void onSteady(object sender, SteadyEventArgs e)
        {
            try
            {
                Console.WriteLine("STEADY {0}", e.StdDev);

            }
            catch (Exception e8)
            {
                Console.WriteLine("Exception: " + e8);
            }
        }

        void onWave(object sender, EventArgs e)
        {
 try {
            outputStream.WriteLine("WAVE");
 
 }
            catch (Exception e9)
            {
                Console.WriteLine("Exception: " + e9);
            }
        }

        void onCircle(object sender, CircleEventArgs e)
        {
             try
            {
            outputStream.WriteLine("ONCIRLCE");
             }
            catch (Exception e10)
            {
                Console.WriteLine("Exception: " + e10);
            }
        }

        void onNoCircle(object sender, NoCircleEventArgs e)
        {
            
            try
            {
                outputStream.WriteLine("NOCIRCLE {0}", e.Reason);
            }
            catch (Exception e11)
            {
                Console.WriteLine("Exception: " + e11);
            }         
        }
    }
}
